﻿using System;
using System.Collections.Generic;
using BaseDomainNamespace.Specifications;
using BaseDomainNamespace.Viewpoints;

namespace BasePersistenceNamespace
{
    /// <summary>
    /// リポジトリを表します。
    /// </summary>
    /// <remarks>
    /// <para>
    /// エンティティの取得、追加対象・削除対象のマークを行うにはリポジトリを使用します。
    /// リポジトリは集約のルートエンティティを扱うため、型パラメータ <typeparamref name="TEntity"/> にはルートエンティティの型を指定します。
    /// 子エンティティの型を指定して使用することも可能ですが、設計上の観点から推奨されません。
    /// </para>
    /// <para>
    /// エンティティのデータストアへの登録や削除は、リポジトリの <see cref="IRepository&lt;TEntity&gt;.Add(TEntity)"/> メソッドや 
    /// <see cref="IRepository&lt;TEntity&gt;.Remove(TEntity)"/> メソッド を使用しますが、
    /// これらのメソッドを呼び出しただけでは操作はデータストアに反映されません。
    /// <see cref="IWorkspace"/> の <see cref="IWorkspace.PersistAll(System.Data.IsolationLevel)"/> メソッドを呼び出すことでデータストアに反映されます。
    /// この時、エンティティへの変更についてもデータストアに反映されます。
    /// </para>
    /// <note type="note">
    /// リポジトリの実装クラスは基本機能として実装されているため、主要機能側アセンブリで実装する必要はありません。
    /// </note>
    /// </remarks>
    /// <typeparam name="TEntity">ルートエンティティの型。</typeparam>
    /// <seealso cref="IWorkspace"/>
    public interface IRepository<TEntity>
        where TEntity : class
    {
        /// <summary>
        /// 指定した仕様を満たす唯一のエンティティを取得します。
        /// </summary>
        /// <param name="specification">満たすべき仕様。</param>
        /// <returns>指定した仕様を満たす唯一のエンティティ。存在しない場合は null。</returns>
        /// <exception cref="System.ArgumentNullException">specification が null です。</exception>
        TEntity Find(Specification<TEntity> specification);

        /// <summary>
        /// 指定した仕様を満たすエンティティの一覧を取得します。
        /// </summary>
        /// <param name="specification">満たすべき仕様。null の場合は全てのエンティティを対象にします。</param>
        /// <param name="order">並べ替えの基準となる順序。</param>
        /// <param name="skipCount">取得対象から除外する要素数。</param>
        /// <param name="takeCount">取得する要素数。</param>
        /// <returns>指定した仕様を満たすエンティティの一覧。</returns>
        List<TEntity> FindList(Specification<TEntity> specification, Order<TEntity> order = null, int? skipCount = null, int? takeCount = null);

        /// <summary>
        /// 全てのエンティティを取得します。
        /// </summary>
        /// <param name="order">並べ替えの基準となる順序。</param>
        /// <param name="skipCount">取得対象から除外する要素数。</param>
        /// <param name="takeCount">取得する要素数。</param>
        /// <returns>エンティティの一覧。</returns>
        List<TEntity> FindAll(Order<TEntity> order = null, int? skipCount = null, int? takeCount = null);


        /// <summary>
        /// 指定した仕様を満たすエンティティが存在するかどうかを示す値を取得します。
        /// </summary>
        /// <param name="specification">満たすべき仕様。</param>
        /// <returns>指定した仕様を満たすエンティティが存在する場合は true、それ以外は false。</returns>
        bool Exists(Specification<TEntity> specification);

        /// <summary>
        /// 指定した仕様を満たすエンティティの要素数を取得します。
        /// </summary>
        /// <param name="specification">満たすべき仕様。</param>
        /// <returns>指定した仕様を満たすエンティティの数。</returns>
        int GetCount(Specification<TEntity> specification);


        /// <summary>
        /// 指定したエンティティを追加対象としてマークします。
        /// </summary>
        /// <param name="target">追加対象のエンティティ。</param>
        void Add(TEntity target);

        /// <summary>
        /// 指定したエンティティを削除対象としてマークします。
        /// </summary>
        /// <param name="target">削除対象のエンティティ。</param>
        void Remove(TEntity target);
    }
}
